#pragma once

#include "Singleton.h"
#include "MapInstance.h"
#include "MapInstanceWorker.h"

class InstanceMgr : public ThreadPool, public Singleton<InstanceMgr>
{
public:
	InstanceMgr();
	virtual ~InstanceMgr();

	MapInstance* CreateAndGetInstance(uint32 mapType, uint32 mapId,
		uint32 instUid = INST_UID_INVALID, ObjGUID instOwner = ObjGUID_NULL);

	MapInstance* CreateInstance(uint32 mapType, uint32 mapId,
		uint32 instUid = INST_UID_INVALID, ObjGUID instOwner = ObjGUID_NULL);
	void RemoveInstance(MapInstance* pMapInstance);

	void StartInstance(InstGUID fakeInstGuid, ObjGUID instOwner = ObjGUID_NULL,
		uint32 flags = 0, const std::string_view& args = emptyStringView,
		const std::function<void(bool, InstGUID)>& resp = nullptr);
	void StopInstance(InstGUID instGuid);

	MapInstance* GetMapInstance(InstGUID instGuid) const;
	MapInstance* GetMapInstance(
		uint32 mapType, uint32 mapId, ObjGUID instOwner) const;

	void ForeachAllInstance(const std::function<void(MapInstance*)>& func) const;
	void ForeachAllPlayer(const std::function<void(Player*)>& func) const;

private:
	virtual bool Prepare();

	const GameMap* CreateAndGetDeferGameMap(uint32 mapId);

	MapInstance* GetAppropriateMapInstance(uint32 mapType, uint32 mapId);
	MapInstance* GetAppropriateMapInstance4WorldMap(uint32 mapId);

	IMapHook* CreateMapHook(MapInstance* pMapInstance) const;
	MapInstanceWorker* GetLoadWorkerLowest() const;

	static bool CanAutoCreateMapInstance(uint32 mapType, uint32 mapId);
	static bool CanPriorCreateMapInstance(uint32 mapType, uint32 mapId);

	mutable std::shared_mutex m_mapSharedMutex;
	std::unordered_map<InstGUID, MapInstance*> m_mapInstances;
	std::unordered_multimap<ObjGUID, MapInstance*> m_mapOwners;

	std::unordered_map<uint32, GameMap*> m_gameMaps;

	uint32 m_instSeed;
};

#define sInstanceMgr (*InstanceMgr::instance())
